//
// Created by 余代宸 -Yu DaiChen on 2021/12/18
// QQ-E-MAIL:250074249@qq.com
//


#include "utils/simpleUtils.h"

/**
 * @brief 有两种方法创建互斥锁，静态方式和动态方式。
 * POSIX定义了一个宏PTHREAD_MUTEX_INITIALIZER来静态初始化互斥锁，方法如下：
 * pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;
 * 在LinuxThreads实现中，pthread_mutex_t是一个结构，而PTHREAD_MUTEX_INITIALIZER则是一个结构常量。
 *		PTHREAD_MUTEX_NORMAL ： 不提供死锁检测
 * 		PTHREAD_MUTEX_ERRORCHECK ：提供错误检查，尝试重新锁定的互斥锁已经由该线程锁定 或者 解除锁定的互斥锁不是由该线程锁定或者未锁定 返回错误
 * 		PTHREAD_MUTEX_RECURSIVE ：锁定计数，锁住 +1 ，解除 -1 ，0可以获取
 * 		PTHREAD_MUTEX_DEFAULT ： 以递归方式锁定，尝试解除对它的锁定、解除锁定尚未锁定的互斥锁，则会产生不确定的行为
 * POSIX这个名称是由理查德·斯托曼（RMS）应IEEE的要求而提议的一个易于记忆的名称。
 * 它基本上是Portable Operating System Interface（可移植操作系统接口）的缩写，而X则表明其对Unix API的传承
 */
#ifdef __unix__
pthread_mutex_t logFileMutex = PTHREAD_MUTEX_INITIALIZER;
#endif //__unix__

int voidPointToInt(void *val) {
	int tmp;
	memcpy(&tmp, (void *) &val, 4);
	return tmp;
}

void logUtils(const char *str, enum LogLevel level) {
	char *levelStr;
	switch (level) {
		case LOG_ERROR:
			levelStr = "[ERROR]:\t";
			break;
		case LOG_WARN:
			levelStr = "[WARN]:\t";
			break;
		case LOG_INFO:
			levelStr = "[INFO]:\t";
			break;
		case LOG_DEBUG:
			levelStr = "[DEBUG]:\t";
			break;
		default:
			levelStr = "[DEBUG]:\t";
	};
	char *logChar = (char *) malloc(strlen(str) + strlen(levelStr) + 1);
	strcat(logChar, levelStr);
	strcat(logChar, str);
	privateWriteLogFile(logChar);
#ifdef __DEBUG_EXEC
	printf("%s\n", logChar);
#endif
	if (logChar != NULL) {
		free(logChar);
		logChar = NULL;
	}
}

long getFileSize(const char *filename) {
	long length = 0;
	FILE *fp = NULL;
	fp = fopen(filename, "rb");
	if (fp != NULL) {
		fseek(fp, 0, SEEK_END);
		length = ftell(fp);
	}
	if (fp != NULL) {
		fclose(fp);
		fp = NULL;
	}
	return length;
}

void getLocalTime(char *val) {
	time_t currentTime;
	struct tm *timeInfo;
	time(&currentTime);
	timeInfo = localtime(&currentTime);
	sprintf(val, "%04d-%02d-%02d %02d:%02d:%02d",
	        (timeInfo->tm_year + 1900), timeInfo->tm_mon, timeInfo->tm_mday,
	        timeInfo->tm_hour, timeInfo->tm_min, timeInfo->tm_sec);
}

void privateWriteLogFile(const char *val) {
	const char *filename = LOG_FILE_PATH;
	if (filename != NULL && val != NULL) {
		// 文件超过最大限制, 删除
		if (getFileSize(filename) > FILE_MAX_SIZE) {
			unlink(filename); // 删除文件
		}
#ifdef __unix__
		pthread_mutex_lock(&logFileMutex);
#endif // __unix__
		// 写日志
		FILE *fp;
		fp = fopen(filename, "at+");
		if (fp != NULL) {
			char now[32];
			memset(now, 0, sizeof(now));
			getLocalTime(now);
			fputs(now, fp);
			fputs(val, fp);
#ifdef _WIN32
			fputs("\r\n", fp);
#else
			fputs("\n", fp);
#endif // _WIN32
			fclose(fp);
			fp = NULL;
		}
#ifdef __unix__
		pthread_mutex_unlock(&logFileMutex);
#endif // __unix__
	}
}